﻿#define _CRT_SECURE_NO_WARNINGS 1

//一、冯诺依曼体系结构 

//我们常见的计算机，如笔记本。我们不常见的计算机，如服务器，大部分都遵守冯诺依曼体系

//截至目前，我们所认识的计算机，都是由一个个的硬件组件组成
//• 输入单元：包括键盘, ⿏标，扫描仪, 写板等
//• 中央处理器(CPU)：含有运算器和控制器等
//• 输出单元：显示器，打印机等

//上面的五大部件，他们都是分开的，那要让他们各个部件连接起来，需要用到“线”，这个线就叫总线
//总线分为两种：1.系统总线，2.IO总线


//注意：：
//• 这里的存储器指的是内存
//• 不考虑缓存情况，这里的CPU能且只能对内存进⾏读写，不能访问外设(输入或输出设备)(数据层面)
//• 外设(输入或输出设备)要输入或者输出数据，也只能写⼊内存或者从内存中读取
//• 一句话，所有设备都只能直接和内存打交道。
//• 正是因为冯诺依曼体系结构，所以程序要运行必须先加载到内存中

 //二、操作系统(Operator System)
//2.1概念

//任何计算机系统都包含一个基本的程序集合，称为操作系统(OS)。笼统的理解，操作系统包括：
//• 内核（进程管理，内存管理，文件管理，驱动管理）
//• 其他程序（例如函数库，shell程序等等）

//2.2设计OS的目的
//• 对下，与硬件交互，管理所有的软硬件资源
//• 对上，为用户程序（应用程序）提供一个良好的执行环境

//2.3核心功能

//• 在整个计算机软硬件架构中，操作系统的定位是：一款纯正的“搞管理”的软件

//2.4如何理解"管理"

//• 描述被管理对象
//• 组织被管理对象
//• 先描述，在组织

//总结：计算机管理硬件
//1. 描述起来，用struct结构体
//2. 组织起来，用链表或其它高效的数据结构

//2.5系统调用和库函数概念

//• 在开发角度，操作系统对外会表现为一个整体，但是会暴露自己的部分接口，供上层开发使用，
//这部分由操作系统提供的接口，叫做系统调用。
//• 系统调用在使用上，功能比较基础，对用户的要求相对也比较高，所以，有心的开发者可以对部
//分系统调用进行适度封装，从而形成库，有了库，就很有利于更上层用户或者开发者进行二次开发。

//三、进程

//3.1基本概念与基本操作

//• 内核观点：担当分配系统资源（CPU时间，内存）的实体
//• 当前：进程 = 内核数据结构(task_struct) + 自己的程序代码和数据

//3.2描述进程-PCB

//基本概念
//• 进程信息被放在一个叫做进程控制块的数据结构中，可以理解为进程属性的集合。
//• 课本上称之为PCB（process control block），Linux操作系统下的PCB是:task_struct

//task_struct-PCB的一种
//• 在Linux中描述进程的结构体叫做task_struct 
//• task_struct 是Linux内核的一种数据结构类型，它会被装载到RAM(内存)里并且包含着进程的信息。

//3.3task_struct
//内容分类
//• 标识符：描述本进程的唯一标识符，用来区别其他进程。
//• 状态:任务状态，退出代码，退出信号等
//• 优先级: 相对于其他进程的优先级
//• 程序计数器: 程序中即将被执行的下一条指令的地址
//• 内存指针:包括程序代码和进程相关数据的指针，还有和其他进程共享的内存块的指针
//• 上下文数据:进程执行时处理器的寄存器中的数据[休学例子，要加图CPU，寄存器]
//• I/O状态信息:包括显示的I/O请求, 分配给进程的I/O设备和被进程使用的文件列表
//• 记账信息:可能包括处理器时间总和，使用的时钟数总和，时间限制，记账号等
//• 其他信息：具体详细信息后续会介绍

//可以在内核源代码里找到它。所有运行在系统里的进程都以 task_struct 双链表的形式存在内核里

//3.4查看进程

//1.进程的信息可以通过/proc系统文件夹查看
//如：要获取PID为1的进程信息，你需要查看/proc/1这个文件夹

//2. 大多数进程信息同样可以使用top和ps这些用户级工具来获取

//3.5通过系统调用获取进程标示符

//• 进程id（PID）
//• 父进程id（PPID）
#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
int main()
{
	printf("pid: %d\n", getpid());
	printf("ppid: %d\n", getppid());
	return 0;
}

//3.6通过系统调用创建进程-fork初识

//• 运行 man fork 认识fork
//• fork有两个返回值
//• 父子进程代码共享，数据各自开辟空间，私有一份（采用写时拷贝）

#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
int main()
{
	int ret = fork();
	printf("hello proc : %d!, ret: %d\n", getpid(), ret);
	sleep(1);
	return 0;
}

//• 由于fork会返回两个id值，所以fork之后通常要用if进行分流
#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>
int main()
{
	int ret = fork();
	if (ret < 0) {
		perror("fork");
		return 1;
	}
	else if (ret == 0) { //child
		printf("I am child : %d!, ret: %d\n", getpid(), ret);
	}
	else { //father
		printf("I am father : %d!, ret: %d\n", getpid(), ret);
	}
	sleep(1);
	return 0;
}